package rpc.core.plugin.impl.proxy;

import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import org.springframework.data.redis.core.StringRedisTemplate;
import rpc.core.FlowReq;
import rpc.core.FlowRes;

/*********
 *
 *
 *@author 197
 *@date 2020/8/4 12:46
 *
 **/


public class RedisStringRedisTemplateServiceProxy {

  private final StringRedisTemplate redisTemplate;

  public RedisStringRedisTemplateServiceProxy(StringRedisTemplate redisTemplate) {
    this.redisTemplate = redisTemplate;
  }

  /***
   * set  String
   * @param req ->[key ,value,timeout ], TimeUnit.MILLISECONDS
   * @return ok()
   */
  public FlowRes set(FlowReq req) {
    this.redisTemplate.opsForValue().set(req.ns("key"), req.ns("value"));
    return new FlowRes();
  }

  public FlowRes setAndTime(FlowReq req) {
    this.redisTemplate.opsForValue().set(req.ns("key"), req.ns("value"), req.l("timeout", 3000), TimeUnit.MILLISECONDS);
    return new FlowRes();
  }

  /****
   * multiSet String
   * @param req -> k , v
   * @return ok()
   */
  public FlowRes mset(FlowReq req) {
    Map<String, Object> entries = req.toMap();
    Map<String, String> tmp = new HashMap<>();
    entries.forEach((k, v) -> tmp.put(k, String.valueOf(v)));
    this.redisTemplate.opsForValue().multiSet(tmp);
    return new FlowRes();
  }

  /***
   * get String
   * @param req  -> key
   * @return "value":value
   */
  public FlowRes get(FlowReq req) {
    String value = this.redisTemplate.opsForValue().get(req.ns("key"));
    return new FlowRes().append("value", value);
  }

  /*****
   * multiGet  String
   * @param req ->keys ["",""]
   * @return values:["",""]
   */
  public FlowRes mget(FlowReq req) {
    List<String> values = this.redisTemplate.opsForValue().multiGet(req.ls("keys"));
    return new FlowRes().append("values", values);
  }

  /***
   * set  String
   * @param req ->[key ,value,timeout ], TimeUnit.SECONDS
   * @return retCode
   */
  public FlowRes setNx(FlowReq req) {
    Boolean isSuccess = this.redisTemplate.opsForValue().setIfAbsent(req.ns("key"), req.ns("value"), req.l("timeout"), TimeUnit.SECONDS);
    int retCode = isSuccess != null && isSuccess ? 0 : -810;
    return new FlowRes().append("retCode", retCode).append("retMsg", retCode != 0 ? "key exists" : "");
  }

  /***
   * key 释放存在
   * @param req -> key
   * @return ok()
   */
  public FlowRes exists(FlowReq req) {
    Boolean hasKey = this.redisTemplate.hasKey(req.ns("key"));
    int retCode = hasKey != null && hasKey ? 0 : -811;
    return new FlowRes().append("retCode", retCode).append("retMsg", retCode != 0 ? "key not exists" : "");
  }


  public FlowRes expire(FlowReq req) {
    long expire = req.l("expire");
    String key = req.ns("key");
    Boolean aBoolean = this.redisTemplate.expire(key, expire, TimeUnit.MILLISECONDS);
    int retCode = aBoolean != null && aBoolean ? 0 : -99812;
    return new FlowRes().fail(retCode).msg(retCode == 0 ? "" : "key not exists");
  }

  public FlowRes persist(FlowReq req) {
    Boolean persist = this.redisTemplate.persist(req.ns("key"));
    int retCode = persist != null && persist ? 0 : -99812;
    return new FlowRes().fail(retCode).msg(retCode == 0 ? "" : "key not exists");
  }

  public FlowRes getSet(FlowReq req) {
    String gs = this.redisTemplate.opsForValue().getAndSet(req.ns("key"), req.ns("value"));
    return new FlowRes().append("value", gs);
  }

  public FlowRes incrBy(FlowReq req) {
    Long increment = this.redisTemplate.opsForValue().increment(req.ns("key"), req.l("step", 1));
    return new FlowRes().append("value", increment);
  }

  public FlowRes decrBy(FlowReq req) {
    Long increment = this.redisTemplate.opsForValue().decrement(req.ns("key"), req.l("step", 1));
    return new FlowRes().append("value", increment);
  }

  public FlowRes strLen(FlowReq req) {
    Long increment = this.redisTemplate.opsForValue().size(req.ns("key"));
    return new FlowRes().append("value", increment);
  }

  public FlowRes hmSet(FlowReq req) {
    this.redisTemplate.opsForHash().putAll(req.ns("key"), req.nm("value"));
    return new FlowRes();
  }

  public FlowRes hSet(FlowReq req) {
    this.redisTemplate.opsForHash().put(req.ns("key"), req.ns("field"), req.ns("value"));
    return new FlowRes();
  }

  public FlowRes hSetNx(FlowReq req) {
    this.redisTemplate.opsForHash().putIfAbsent(req.ns("key"), req.ns("field"), req.ns("value"));
    return new FlowRes();
  }

  public FlowRes hGetAll(FlowReq req) {
    Map<Object, Object> values = this.redisTemplate.opsForHash().entries(req.ns("key"));
    return new FlowRes().append("values", values);
  }

  public FlowRes hGet(FlowReq req) {
    Object values = this.redisTemplate.opsForHash().get(req.ns("key"), req.ns("field"));
    return new FlowRes().append("value", values);
  }

  public FlowRes hDel(FlowReq req) {
    long values = this.redisTemplate.opsForHash().delete(req.ns("key"), req.ls("fields").toArray());
    return new FlowRes().append("value", values);
  }

  public FlowRes hExists(FlowReq req) {
    Boolean aBoolean = this.redisTemplate.opsForHash().hasKey(req.ns("key"), req.ns("field"));
    int retCode = aBoolean ? 0 : -813;
    return new FlowRes().fail(retCode).msg(retCode != 0 ? "key not exists" : "");
  }


  public FlowRes lPush(FlowReq req) {
    Long push = this.redisTemplate.opsForList().leftPush(req.ns("key"), req.ns("value"));
    return new FlowRes().append("value", push);
  }

  public FlowRes lPushAll(FlowReq req) {
    Long push = this.redisTemplate.opsForList().leftPushAll(req.ns("key"), req.ls("values"));
    return new FlowRes().append("value", push);
  }

  public FlowRes rPush(FlowReq req) {
    Long push = this.redisTemplate.opsForList().rightPush(req.ns("key"), req.ns("value"));
    return new FlowRes().append("value", push);
  }

  public FlowRes rPushAll(FlowReq req) {
    Long push = this.redisTemplate.opsForList().rightPushAll(req.ns("key"), req.ls("values"));
    return new FlowRes().append("value", push);
  }

  public FlowRes lPop4Timeout(FlowReq req) {
    String pop = this.redisTemplate.opsForList().leftPop(req.ns("key"), req.l("timeout", 3000), TimeUnit.MILLISECONDS);
    return new FlowRes().append("value", pop);
  }

  public FlowRes lPop(FlowReq req) {
    String pop = this.redisTemplate.opsForList().leftPop(req.ns("key"));
    return new FlowRes().append("value", pop);
  }

  public FlowRes rPop(FlowReq req) {
    String pop = this.redisTemplate.opsForList().rightPop(req.ns("key"));
    return new FlowRes().append("value", pop);
  }

  public FlowRes rPop4Timeout(FlowReq req) {
    String pop = this.redisTemplate.opsForList().rightPop(req.ns("key"), req.l("timeout", 3000), TimeUnit.MILLISECONDS);
    return new FlowRes().append("value", pop);
  }

  public FlowRes lRange(FlowReq req) {
    List<String> strings = this.redisTemplate.opsForList().range(req.ns("key"), req.l("start"), req.l("end"));
    return new FlowRes().append("values", strings);
  }

  public FlowRes lLen(FlowReq req) {
    Long size = this.redisTemplate.opsForList().size(req.ns("key"));
    return new FlowRes().append("value", size);
  }

  // 以下暂无实现
//  lrem mylist count value  删除
//  lindex mylist 2          指定索引的值
//  lset mylist 2 n          索引设值
//  ltrim mylist 0 4         删除key
//  linsert mylist before a  插入
//  linsert mylist after a   插入
//  rpoplpush list list2     转移列表的数据

//  set
//  sadd myset redis
//  smembers myset       数据集合
//  srem myset set1         删除
//  sismember myset set1 判断元素是否在集合中
//  scard key_name       个数
//  sdiff | sinter | sunion 操作：集合间运算：差集 | 交集 | 并集
//  srandmember          随机获取集合中的元素
//  spop                 从集合中弹出一个元素
//
//  zset
//  zadd zset 1 one
//  zadd zset 2 two
//  zadd zset 3 three
//  zincrby zset 1 one              增长分数
//  zscore zset two                 获取分数
//  zrange zset 0 -1 withscores     范围值
//  zrangebyscore zset 10 25 withscores 指定范围的值
//  zrangebyscore zset 10 25 withscores limit 1 2 分页
//  Zrevrangebyscore zset 10 25 withscores  指定范围的值
//  zcard zset  元素数量
//  Zcount zset 获得指定分数范围内的元素个数
//  Zrem zset one two        删除一个或多个元素
//  Zremrangebyrank zset 0 1  按照排名范围删除元素
//  Zremrangebyscore zset 0 1 按照分数范围删除元素
//  Zrank zset 0 -1    分数最小的元素排名为0
//  Zrevrank zset 0 -1  分数最大的元素排名为0
//      Zinterstore
//  zunionstore rank:last_week 7 rank:20150323 rank:20150324 rank:20150325  weights 1 1 1 1 1 1 1

}
